// Fill out your copyright notice in the Description page of Project Settings.


#include "DelegateMaker.h"
#include "DelegateObject.h"

class RawObject
{
public:
	void DelegateTest()
	{
		UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__));
	}

	void DelegateTest(bool Value)
	{
		UE_LOG(LogTemp, Warning, TEXT("%s, bool=%u"), TEXT(__FUNCTION__), Value);
	}

	static void DelegateStatic()
	{
		UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__));
	}

	static void DelegateStatic(bool Value)
	{
		UE_LOG(LogTemp, Warning, TEXT("%s, bool=%u"), TEXT(__FUNCTION__), Value);
	}
};

FTestMultiDelegate& UDelegateMaker::AddMultiDelegate()
{
	FString FuncName(TEXT(__FUNCTION__));
	if (UEObject == nullptr)
	{
		UEObject = NewObject<UDelegateObject>();
	}
	TestMultiDelegate.AddUObject(UEObject, &UDelegateObject::TestMultiDelegate_Ret_PBool_Payload, 100);
	TestMultiDelegate.AddLambda(
		[FuncName](bool Value) {
			UE_LOG(LogTemp, Warning, TEXT("%s in Lambda, bool=%u"), *FuncName, Value);
		}
	);
	if (!RawObjectPtr.IsValid()) {
		RawObjectPtr = MakeShareable(new RawObject);
	}
	TestMultiDelegate.AddRaw(RawObjectPtr.Get(), &RawObject::DelegateTest);
	TestMultiDelegate.AddSP(RawObjectPtr.ToSharedRef(), &RawObject::DelegateTest);
	TestMultiDelegate.AddStatic(&RawObject::DelegateStatic);
	TestMultiDelegate.AddUFunction(UEObject, "TestMultiDelegate_Ret_PBool_Payload", 200);
	TestMultiDelegate.AddWeakLambda(UEObject,
		[FuncName](bool Value) {
			UE_LOG(LogTemp, Warning, TEXT("%s in Lambda, bool=%u"), *FuncName, Value);
		}
	);
	return TestMultiDelegate;
}

FTestDynamicMultiDelegate& UDelegateMaker::AddMultiDynamicDelegate()
{
	if (UEObject == nullptr)
	{
		UEObject = NewObject<UDelegateObject>();
	}
	TestDynamicMultiDelegate.AddDynamic(UEObject, &UDelegateObject::TestMultiDelegate_Ret_PBool);
	return TestDynamicMultiDelegate;
}

void UDelegateMaker::InvokeEvent(bool Value)
{
	FString FuncName(TEXT(__FUNCTION__));
	UDelegateMaker* Maker = this;
	FTestEvent& Event = Maker->OnTestEvent();
	if (UEObject == nullptr)
	{
		UEObject = NewObject<UDelegateObject>();
	}
	Event.AddUObject(UEObject, &UDelegateObject::TestMultiDelegate_Ret_PBool_Payload, 300);
	Event.AddLambda(
		[FuncName](bool Value) {
			UE_LOG(LogTemp, Warning, TEXT("%s in Lambda, bool=%u"), *FuncName, Value);
		}
	);
	if (!RawObjectPtr.IsValid()) {
		RawObjectPtr = MakeShareable(new RawObject);
	}
	Event.AddRaw(RawObjectPtr.Get(), &RawObject::DelegateTest);
	Event.AddSP(RawObjectPtr.ToSharedRef(), &RawObject::DelegateTest);
	Event.AddStatic(&RawObject::DelegateStatic);
	Event.AddUFunction(UEObject, "TestMultiDelegate_Ret_PBool_Payload", 400);
	Event.AddWeakLambda(UEObject,
		[FuncName](bool Value) {
			UE_LOG(LogTemp, Warning, TEXT("%s in Lambda, bool=%u"), *FuncName, Value);
		}
	);
	TestEvent.Broadcast(Value);
}

FTestDynamicDelegate& UDelegateMaker::MakeDynamicDelegate()
{
	if (!TestDynamicDelegate.IsBound())
	{
		TestDynamicDelegate.Unbind();
	}
	if (UEObject == nullptr)
	{
		UEObject = NewObject<UDelegateObject>();
	}
	TestDynamicDelegate.BindDynamic(UEObject, &UDelegateObject::TestDelegate_Ret_PBool);
	return TestDynamicDelegate;
}

FTestDelegate& UDelegateMaker::MakeDelegate(EDelegateType Type)
{
	if (Delegate.IsBound())
	{
		Delegate.Unbind();
	}
	switch (Type) {
	case EDelegateType::Object:
		if (UEObject == nullptr)
		{
			UEObject = NewObject<UDelegateObject>();
		}
		Delegate.BindUObject(UEObject, &UDelegateObject::TestDelegate);
		break;

	case	EDelegateType::Lambda:
		Delegate.BindLambda(
			[](void)
			{
				UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__));
			}
		);
		break;

	case EDelegateType::Raw:
		if (!RawObjectPtr.IsValid()) {
			RawObjectPtr = MakeShareable(new RawObject);
		}
		Delegate.BindRaw(RawObjectPtr.Get(), &RawObject::DelegateTest);
		break;

	case EDelegateType::SP:
		if (!RawObjectPtr.IsValid()) {
			RawObjectPtr = MakeShareable(new RawObject);
		}
		Delegate.BindSP(RawObjectPtr.ToSharedRef(), &RawObject::DelegateTest);
		break;

	case EDelegateType::Static:
		Delegate.BindStatic(&RawObject::DelegateStatic);
		break;

	case EDelegateType::UFunction:
		if (UEObject == nullptr)
		{
			UEObject = NewObject<UDelegateObject>();
		}
		Delegate.BindUFunction(UEObject, "TestDelegateUFunction");
		break;

	case EDelegateType::WeakLambda:
		if (UEObject == nullptr)
		{
			UEObject = NewObject<UDelegateObject>();
		}
		Delegate.BindWeakLambda(UEObject, [](void)
			{
				UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__));
			}
		);
		break;

	default:
		break;
	}
	return Delegate;
}

FTestDelegate_Ret& UDelegateMaker::MakeDelegate_Ret()
{
	if (Delegate_Ret.IsBound())
	{
		Delegate_Ret.Unbind();
	}
	if (UEObject == nullptr)
	{
		UEObject = NewObject<UDelegateObject>();
	}
	Delegate_Ret.BindUObject(UEObject, &UDelegateObject::TestDelegate_Ret);
	return Delegate_Ret;
}

FTestDelegate_Bool& UDelegateMaker::MakeDelegate_Bool()
{
	if (Delegate_Bool.IsBound())
	{
		Delegate_Bool.Unbind();
	}
	if (UEObject == nullptr)
	{
		UEObject = NewObject<UDelegateObject>();
	}
	Delegate_Bool.BindUObject(UEObject, &UDelegateObject::TestDelegate_Bool, 16);
	return Delegate_Bool;
}

FTestDelegate& UDelegateMaker::MakeDelegate_Payload(int Param)
{
	if (Delegate.IsBound())
	{
		Delegate.Unbind();
	}
	if (UEObject == nullptr)
	{
		UEObject = NewObject<UDelegateObject>();
	}
	Delegate.BindUObject(UEObject, &UDelegateObject::TestDelegate_Payload, Param);
	return Delegate;
}
